package com.googlecode.cardamomo.ermodel;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.transform.stream.StreamSource;

/**
 * DataDictionary represent a list of known data types in a given scope
 * 
 * @author jtorne
 *
 */
@XmlRootElement(
	name="datadictionary",
	namespace=DataType.CARDAMOMO_NAMESPACE)
public class DataDictionary {
	
	private String packageName = null;
	
	private static DataDictionary globalInstance = null;
	
	private Vector<DataType> datatypes = new Vector<DataType>();
	
	@XmlTransient
	private Map<String,DataType> entries = new HashMap<String,DataType>();
	
	private DataDictionary parentDict = null;

	public static DataDictionary defaultInstance() {
		if (globalInstance == null) {
			globalInstance = new DataDictionary();
			globalInstance.addEntry(new DataType("int",BasicType.INT,false,false,1, true));
			globalInstance.addEntry(new DataType("smallint",BasicType.INT,false,false,1, true));
			globalInstance.addEntry(new DataType("tinyint",BasicType.INT,false,false,1, true));
			globalInstance.addEntry(new DataType("bigint", BasicType.BIGINT, false, false, 1, true));
			globalInstance.addEntry(new DataType("float", BasicType.FLOAT, false, false,1, true));
			globalInstance.addEntry(new DataType("char",BasicType.CHAR, false, false,1, false));
			globalInstance.addEntry(new DataType("decimal", BasicType.DECIMAL, false, false, 1, true));
			globalInstance.addEntry(new DataType("date", BasicType.DATE, false, false, 1, false));
			globalInstance.addEntry(new DataType("numeric", BasicType.NUMERIC, false, false, 1, true));
			globalInstance.addEntry(new DataType("number", BasicType.NUMERIC, false, false, 1, true));
			globalInstance.addEntry(new DataType("varchar", BasicType.VARCHAR, false, false, 1, false));
			globalInstance.addEntry(new DataType("varchar2", BasicType.VARCHAR, false, false, 1, false));
			globalInstance.addEntry(new DataType("char() for bit data", BasicType.CHAR, false, false, 1, false));
		}
		return globalInstance;
	}

	@XmlTransient
	public DataDictionary getParentDict() {
		return parentDict;
	}

	public void setParentDict(DataDictionary parentDict) {
		this.parentDict = parentDict;
	}
	
	@XmlElementWrapper(name="datatypes")
	@XmlElement(name="datatype")
	public Vector<DataType> getDatatypes() {
		return datatypes;
	}

	public void setDatatypes(Vector<DataType> datatypes) {
		this.datatypes = datatypes;
	}

	public void addEntry(DataType dt) {
		entries.put(dt.getName(), dt);
	}
	
	public DataType getType (String name)
	{
		if (entries.containsKey(name))
			return entries.get(name);
		if ((globalInstance != null) && (this != globalInstance))
			return globalInstance.getType(name);
		return null;
	}
	
	public static DataDictionary importDictionary(String name) {
		
		try {
			JAXBContext jc = JAXBContext.newInstance("cardamomo.googlecode.com");
			Unmarshaller u = jc.createUnmarshaller();
			String path = System.getenv("DDPATH");
			if (path == null) path = ".";
			path = path + "/" + name.replaceAll("[.]", "/")+ ".xdd";
//			System.err.println("Importing from "+path);
			JAXBElement<DataDictionary> jdd = u.unmarshal(new StreamSource(new File(path)),DataDictionary.class);
			return jdd.getValue();
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	@XmlAttribute(name="package",required=true)
	public String getPackageName() {
		return packageName;
	}

	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}

	public Collection<DataType> getTypes() {
		return entries.values();
	}
}
